; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -instcombine < %s | FileCheck %s

; Check that we don't create two redundant phi nodes when %val is used in a
; form where we can't rewrite it in terms of the new phi node.

; Use %val in an instruction type not supported by optimizeBitCastFromPhi.
define float @sitofp(float %x) {
; CHECK-LABEL: @sitofp(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
; CHECK:       loop_header:
; CHECK-NEXT:    [[VAL:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[VAL_INCR_CASTED:%.*]], [[LOOP:%.*]] ]
; CHECK-NEXT:    [[VAL_CASTED:%.*]] = bitcast i32 [[VAL]] to float
; CHECK-NEXT:    [[CMP:%.*]] = fcmp ogt float [[VAL_CASTED]], [[X:%.*]]
; CHECK-NEXT:    br i1 [[CMP]], label [[END:%.*]], label [[LOOP]]
; CHECK:       loop:
; CHECK-NEXT:    [[VAL_INCR:%.*]] = fadd float [[VAL_CASTED]], 1.000000e+00
; CHECK-NEXT:    [[VAL_INCR_CASTED]] = bitcast float [[VAL_INCR]] to i32
; CHECK-NEXT:    br label [[LOOP_HEADER]]
; CHECK:       end:
; CHECK-NEXT:    [[RESULT:%.*]] = sitofp i32 [[VAL]] to float
; CHECK-NEXT:    ret float [[RESULT]]
;
entry:
  br label %loop_header
loop_header:
  %val = phi i32 [ 0, %entry ], [ %val_incr_casted, %loop ]
  %val_casted = bitcast i32 %val to float
  %cmp = fcmp ogt float %val_casted, %x
  br i1 %cmp, label %end, label %loop
loop:
  %val_incr = fadd float %val_casted, 1.0
  %val_incr_casted = bitcast float %val_incr to i32
  br label %loop_header
end:
  %result = sitofp i32 %val to float
  ret float %result
}

; Use %val in an incompatible bitcast.
define <2 x i16> @bitcast(float %x) {
; CHECK-LABEL: @bitcast(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
; CHECK:       loop_header:
; CHECK-NEXT:    [[VAL:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[VAL_INCR_CASTED:%.*]], [[LOOP:%.*]] ]
; CHECK-NEXT:    [[VAL_CASTED:%.*]] = bitcast i32 [[VAL]] to float
; CHECK-NEXT:    [[CMP:%.*]] = fcmp ogt float [[VAL_CASTED]], [[X:%.*]]
; CHECK-NEXT:    br i1 [[CMP]], label [[END:%.*]], label [[LOOP]]
; CHECK:       loop:
; CHECK-NEXT:    [[VAL_INCR:%.*]] = fadd float [[VAL_CASTED]], 1.000000e+00
; CHECK-NEXT:    [[VAL_INCR_CASTED]] = bitcast float [[VAL_INCR]] to i32
; CHECK-NEXT:    br label [[LOOP_HEADER]]
; CHECK:       end:
; CHECK-NEXT:    [[RESULT:%.*]] = bitcast i32 [[VAL]] to <2 x i16>
; CHECK-NEXT:    ret <2 x i16> [[RESULT]]
;
entry:
  br label %loop_header
loop_header:
  %val = phi i32 [ 0, %entry ], [ %val_incr_casted, %loop ]
  %val_casted = bitcast i32 %val to float
  %cmp = fcmp ogt float %val_casted, %x
  br i1 %cmp, label %end, label %loop
loop:
  %val_incr = fadd float %val_casted, 1.0
  %val_incr_casted = bitcast float %val_incr to i32
  br label %loop_header
end:
  %result = bitcast i32 %val to <2 x i16>
  ret <2 x i16> %result
}

@global = global i32 0

; Use %val with a volatile store.
define void @store_volatile(float %x) {
; CHECK-LABEL: @store_volatile(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
; CHECK:       loop_header:
; CHECK-NEXT:    [[VAL:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[VAL_INCR_CASTED:%.*]], [[LOOP:%.*]] ]
; CHECK-NEXT:    [[VAL_CASTED:%.*]] = bitcast i32 [[VAL]] to float
; CHECK-NEXT:    [[CMP:%.*]] = fcmp ogt float [[VAL_CASTED]], [[X:%.*]]
; CHECK-NEXT:    br i1 [[CMP]], label [[END:%.*]], label [[LOOP]]
; CHECK:       loop:
; CHECK-NEXT:    [[VAL_INCR:%.*]] = fadd float [[VAL_CASTED]], 1.000000e+00
; CHECK-NEXT:    [[VAL_INCR_CASTED]] = bitcast float [[VAL_INCR]] to i32
; CHECK-NEXT:    br label [[LOOP_HEADER]]
; CHECK:       end:
; CHECK-NEXT:    store volatile i32 [[VAL]], i32* @global, align 4
; CHECK-NEXT:    ret void
;
entry:
  br label %loop_header
loop_header:
  %val = phi i32 [ 0, %entry ], [ %val_incr_casted, %loop ]
  %val_casted = bitcast i32 %val to float
  %cmp = fcmp ogt float %val_casted, %x
  br i1 %cmp, label %end, label %loop
loop:
  %val_incr = fadd float %val_casted, 1.0
  %val_incr_casted = bitcast float %val_incr to i32
  br label %loop_header
end:
  store volatile i32 %val, i32* @global
  ret void
}

; Use %val with a store where it's actually the address.
define void @store_address(i32 %x) {
; CHECK-LABEL: @store_address(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
; CHECK:       loop_header:
; CHECK-NEXT:    [[VAL:%.*]] = phi i32* [ @global, [[ENTRY:%.*]] ], [ [[VAL_INCR1:%.*]], [[LOOP:%.*]] ]
; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 0
; CHECK-NEXT:    br i1 [[CMP]], label [[END:%.*]], label [[LOOP]]
; CHECK:       loop:
; CHECK-NEXT:    [[VAL_INCR1]] = getelementptr i32, i32* [[VAL]], i64 1
; CHECK-NEXT:    br label [[LOOP_HEADER]]
; CHECK:       end:
; CHECK-NEXT:    store i32 0, i32* [[VAL]], align 4
; CHECK-NEXT:    ret void
;
entry:
  br label %loop_header
loop_header:
  %val = phi i32* [ @global, %entry ], [ %val_incr_casted, %loop ]
  %i = phi i32 [ 0, %entry ], [ %i_incr, %loop ]
  %val_casted = bitcast i32* %val to float*
  %cmp = icmp sgt i32 %i, %x
  br i1 %cmp, label %end, label %loop
loop:
  %i_incr = add i32 %i, 0
  %val_incr = getelementptr float, float* %val_casted, i32 1
  %val_incr_casted = bitcast float* %val_incr to i32*
  br label %loop_header
end:
  store i32 0, i32* %val
  ret void
}

; Test where a phi (%val2) other than the original one (%val) has an
; incompatible use.
define i32 @multiple_phis(float %x) {
; CHECK-LABEL: @multiple_phis(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
; CHECK:       loop_header:
; CHECK-NEXT:    [[VAL:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[VAL2:%.*]], [[LOOP_END:%.*]] ]
; CHECK-NEXT:    [[VAL_CASTED:%.*]] = bitcast i32 [[VAL]] to float
; CHECK-NEXT:    [[CMP:%.*]] = fcmp ogt float [[VAL_CASTED]], [[X:%.*]]
; CHECK-NEXT:    br i1 [[CMP]], label [[END:%.*]], label [[LOOP:%.*]]
; CHECK:       loop:
; CHECK-NEXT:    [[CMP2:%.*]] = fcmp ogt float [[VAL_CASTED]], 2.000000e+00
; CHECK-NEXT:    br i1 [[CMP2]], label [[IF:%.*]], label [[LOOP_END]]
; CHECK:       if:
; CHECK-NEXT:    [[VAL_INCR:%.*]] = fadd float [[VAL_CASTED]], 1.000000e+00
; CHECK-NEXT:    [[VAL_INCR_CASTED:%.*]] = bitcast float [[VAL_INCR]] to i32
; CHECK-NEXT:    br label [[LOOP_END]]
; CHECK:       loop_end:
; CHECK-NEXT:    [[VAL2]] = phi i32 [ [[VAL]], [[LOOP]] ], [ [[VAL_INCR_CASTED]], [[IF]] ]
; CHECK-NEXT:    store volatile i32 [[VAL2]], i32* @global, align 4
; CHECK-NEXT:    br label [[LOOP_HEADER]]
; CHECK:       end:
; CHECK-NEXT:    ret i32 [[VAL]]
;
entry:
  br label %loop_header
loop_header:
  %val = phi i32 [ 0, %entry ], [ %val2, %loop_end ]
  %val_casted = bitcast i32 %val to float
  %cmp = fcmp ogt float %val_casted, %x
  br i1 %cmp, label %end, label %loop
loop:
  %cmp2 = fcmp ogt float %val_casted, 2.0
  br i1 %cmp2, label %if, label %loop_end
if:
  %val_incr = fadd float %val_casted, 1.0
  %val_incr_casted = bitcast float %val_incr to i32
  br label %loop_end
loop_end:
  %val2 = phi i32 [ %val, %loop ], [ %val_incr_casted, %if ]
  store volatile i32 %val2, i32* @global ; the incompatible use
  br label %loop_header
end:
  ret i32 %val
}
